package com.idroc.coelacanth.core.message;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 

/**
 * 抽象消息
 * @author 赤脚詹(yuyoo4j@163.com)
 * @date Aug 17, 2009 4:09:15 PM
 * @memo:保证encode或者decode只会被执行一次
 */
public abstract class AbstractMessage implements Message {
	
	private static final Logger log = LoggerFactory.getLogger(AbstractMessage.class); 
	
	/**
	 * 消息自解析
	 * @param ib -- 字节数组
	 * @return -- 消息对象
	 */
	public static Message decodeMessage(ChannelBuffer ib) {
		  	
		int msgId = ib.readInt();
		MessageType type = MessageType.get(msgId);
		if (null == type) {
			String errorMsg = "不能解析消息类型异常:未找到消息类型";
			log.error(errorMsg);
			throw new RuntimeException(errorMsg);
		}
		Class<? extends Message> meta = type.getMsgMeta();
		Message msg = null;
		try {
			msg = meta.newInstance();
			AbstractMessage am = (AbstractMessage)msg;
			am.type = type;
			am.sn = ib.readLong();
			am.decode(ib);
			am.decoded = true;
		} catch (Exception ex) { 
			String errorMsg = "实例化消息异常";
			log.error(errorMsg, ex);
		}
		return msg;
	}
	
	/**
	 * 对消息编码
	 * @param msg -- 消息
	 * @return -- 消息包含编码后字节数组
	 */
	public static ChannelBuffer encodeMessage(Message msg) {
		 
		ChannelBuffer ob = ChannelBuffers.dynamicBuffer(512);
		encodeMessage(msg, ob);
		return ob;
	}
	
	/**
	 * 对消息编码
	 * @param msg -- 消息
	 * @param ob -- 字节数组
	 */
	public static void encodeMessage(Message msg, ChannelBuffer ob) {

		AbstractMessage am = (AbstractMessage)msg;
		ob.writeInt(am.type.getMsgId());
		ob.writeLong(am.sn);
		am.encode(ob);
		am.encoded = true;		
	}

	private long sn = -1;
	
	/**
	 * 消息类型
	 */
	protected MessageType type = null;
	
	/**
	 * 是否解码过标记
	 */
	protected boolean decoded = false;
	
	/**
	 * 是否编码过标记
	 */
	protected boolean encoded = false;
	
	protected AbstractMessage() {
		
		type = MessageType.get(this.getClass());
		if (null == type) {
			// 注册消息类型
			type = MessageType.registry(this.getClass());
		}
		sn = System.currentTimeMillis();
	}

	/**
	 * 解码消息
	 */
	public abstract void decode(ChannelBuffer ib);

	/**
	 * 编码消息
	 */
	public abstract void encode(ChannelBuffer ob);

	/**
	 * 是否解码过
	 */
	public boolean isDecoded() {
		return decoded;
	}

	/**
	 * 是否编码过
	 */
	public boolean isEncoded() {
		return encoded;
	}
	
	/**
	 * 获取消息类型
	 * @return -- 消息类型
	 */
	public MessageType getMsgType() {
		return type;
	} 	
	
	/**
	 * 对字符串编码到通道缓存
	 * @param ob -- 缓存
	 * @param data -- 字符串
	 */
	protected void encodeString(ChannelBuffer ob, String data) {
		
		byte[] buffer = data.getBytes();
		ob.writeShort((short) buffer.length);
		ob.writeBytes(buffer);
	}
	
	/**
	 * 从缓存中解码字符串
	 * @param ib -- 缓存
	 * @return -- 字符串
	 */
	protected String decodeString(ChannelBuffer ib) {
		
		int len = ib.readShort();
		byte[] buffer = new byte[len];
		ib.readBytes(buffer);
		return new String(buffer);
	}
	
	/**
	 *获取消息实体系列号
	 *@return -- 消息系列号
	 */
	public long getSN() {
		return sn;
	}
}
